class WxRequest {
  defaults = {
    baseURL: '', 
    url: '', 
    data: null,
    method: 'GET',
    header: {
      'Content-type': 'application/json' 
    },
    timeout: 60000, // 默认的超时时长，小程序默认的超时时长是 1 分钟
    isLoading: true // 控制是否使用默认的 loading，默认值是 true 表示使用默认的 loading
  }

  interceptors = {
    request: (config) => config,
    response: (response) => response
  }

  queue = []

  constructor(params = {}) {
    this.defaults = Object.assign({}, this.defaults, params)
  }

  request(options) {
    // 如果有新的请求，就清除上一次的定时器
    this.timerId && clearTimeout(this.timerId)
    options.url = this.defaults.baseURL + options.url
    options = { ...this.defaults, ...options }

    if (options.isLoading && options.method !== 'UPLOAD') {
      // 判断 queue 队列是否为空，如果是空，就显示 loading
      // 如果不是空，就不显示 loading，不调用 wx.showLoading()
      this.queue.length === 0 && wx.showLoading()

      // 然后立即向 queue 数组队列中添加请求标识
      // 每个标识代表是一个请求，标识是自定义的
      this.queue.push('request')
    }

    // 在请求发送之前，调用请求拦截器，新增和修改请求参数
    options = this.interceptors.request(options)

    return new Promise((resolve, reject) => {
      if (options.method === 'UPLOAD') {
        wx.uploadFile({
          ...options,

          success: (res) => {
            res.data = JSON.parse(res.data)
            const mergeRes = Object.assign({}, res, {
              config: options,
              isSuccess: true
            })
            resolve(this.interceptors.response(mergeRes))
          },

          fail: (err) => {
            const mergeErr = Object.assign({}, err, {
              config: options,
              isSuccess: false
            })
            reject(this.interceptors.response(mergeErr))
          }
        })
      } else {
        wx.request({
          ...options,
          success: (res) => {
            const mergeRes = Object.assign({}, res, {
              config: options,
              isSuccess: true
            })
            resolve(this.interceptors.response(mergeRes))
          },

          fail: (err) => {
            const mergeErr = Object.assign({}, err, {
              config: options,
              isSuccess: false
            })
            reject(this.interceptors.response(mergeErr))
          },

          complete: () => {
            if (options.isLoading) {
              // 在每一个请求结束以后，都会执行 complete 回调函数
              // 每次从 queue 队列中删除一个标识
              this.queue.pop()

              this.queue.length === 0 && this.queue.push('request')

              this.timerId = setTimeout(() => {
                this.queue.pop()

                // 在删除标识以后，需要判断目前 queue 数组是否为空
                // 如果是空，说明并发请求完成了
                // 就需要隐藏 loading，要调用 wx.hideLoading()
                this.queue.length === 0 && wx.hideLoading()
                clearTimeout(this.timerId)
              }, 1)
            }
          }
        })
      }
    })
  }

  get(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'GET' }, config))
  }

  delete(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
  }

  post(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'POST' }, config))
  }

  put(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'PUT' }, config))
  }

  // 用来处理并发请求
  all(...promise) {
    return Promise.all(promise)
  }

  /**
   * @description upload 实例方法，用来对 wx.uploadFile 进行封装
   * @param {*} url 文件的上传地址、接口地址
   * @param {*} filePath 要上传的文件资源路径
   * @param {*} name 文件对应的 key
   * @param {*} config 其他配置项
   */
  upload(url, filePath, name = 'file', config = {}) {
    return this.request(Object.assign({ url, filePath, name, method: 'UPLOAD' }, config))
  }
}

export default WxRequest
